package com.lezhi.socialgram.service.moments.impl;

import com.lezhi.socialgram.enums.ResultEnum;
import com.lezhi.socialgram.exception.SocialGramException;
import com.lezhi.socialgram.mapper.friend.FriendMapper;
import com.lezhi.socialgram.mapper.moments.MomentMapper;
import com.lezhi.socialgram.model.friend.LikeMe;
import com.lezhi.socialgram.model.moments.Media;
import com.lezhi.socialgram.model.moments.Moment;
import com.lezhi.socialgram.model.moments.Timeline;
import com.lezhi.socialgram.service.friend.FriendService;
import com.lezhi.socialgram.service.moments.MomentService;
import com.lezhi.socialgram.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.GetQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * Created by daizhen on 2017/4/1.
 */
@Service
public class MomentServiceImpl implements MomentService {


    private static final Logger logger = LoggerFactory.getLogger(MomentServiceImpl.class);

    @Autowired
    MomentMapper momentMapper;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    FriendMapper friendMapper;

    static final DefaultRedisScript<Boolean> script = new DefaultRedisScript<Boolean>();

    static final DefaultRedisScript<List> query_script = new DefaultRedisScript<List>();

    static final DefaultRedisScript<List> query_friend_script = new DefaultRedisScript<List>();

    static {
        script.setScriptSource(new ResourceScriptSource(new ClassPathResource(
                "/luascript/timeline.lua")));
        script.setResultType(Boolean.TYPE);

        query_script.setScriptSource(new ResourceScriptSource(new ClassPathResource(
                "/luascript/queryTimelineSelf.lua")));
        query_script.setResultType(List.class);

        query_friend_script.setScriptSource(new ResourceScriptSource(new ClassPathResource(
                "/luascript/queryTimeline.lua")));
        query_friend_script.setResultType(List.class);
    }

    @Override
    public Result publishMoment(Moment moment) {
        try {
            //插入mysql
            //路由到一张表，并拼装一个带有表名信息的id
            TableUtils.Table table = TableUtils.getTableNameWithDate(Moment.class, null);
            String tableName = table.getTableName();
            //获取本周的表名的时间戳(一天之内可能毫秒数不一样，但是yyyy_MM_dd是相同的)
            long time = table.getTime().getTime();
            //获取下一个自增序列
            Long nextMomentSequence = stringRedisTemplate.opsForValue().increment(Param.MOMENT_SEQUENCE, 1);
            //拼装id
            String momentId = time + "_" + nextMomentSequence;
            moment.setMomentId(momentId);
            moment.setCreateTime(new Date());
            moment.setTable(tableName);
            momentMapper.insertMoment(moment);
            //插入elasticsearch
            moment.setCreateTimezone(moment.getCreateTime().getTime());
            elasticsearchTemplate.index(new IndexQueryBuilder().withObject(moment).build());
            //同时执行lua脚本写扩散到时间线
            new Thread(() -> {
                long currentTimeMillis = System.currentTimeMillis();
                //第一个参数 动态id
                //第二个参数 自增id
                String publishTime = nextMomentSequence + "";
                //第三个参数 发布者id
                String publisherId = moment.getUserId() + "";
                //第四个参数 粉丝id的数组
                //查出喜欢我的人的列表，拼接成按逗号分割的字符串
                List<LikeMe> likeMes = friendMapper.queryLikeMe(new LikeMe(TableUtils.getTableNameWithId(LikeMe.class, moment.getUserId(), 100),
                        moment.getUserId()));
                System.out.println("likeMes" + likeMes);
                StringBuffer fansIdStr = new StringBuffer("");
                for (int i = 0; i < likeMes.size(); i++) {
                    if (i == likeMes.size() - 1) {
                        fansIdStr.append(likeMes.get(i));
                    } else {
                        fansIdStr.append(likeMes.get(i) + ",");
                    }
                }
                String fansIds = fansIdStr.toString();
                //第五个参数 动态内容的json
                String momentJson = JsonUtils.objectToJson(moment);
                //第一张图片的url、媒体数量
                Boolean execute = stringRedisTemplate.execute(script, null,
                        momentId,
                        publishTime,
                        publisherId,
                        fansIds,
                        momentJson);
                System.out.println(execute);
            }).start();
            //atSomebody的推送
            List<Long> atSomeOneList = moment.getAtSomeOne_list();
            return ResultUtils.success();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new SocialGramException(ResultEnum.INTERNAL_ERROR);
        }

    }

    @Override
    public Result queryMomentsByUserId(Long userId, Long sequence, Integer operation) {
        if (sequence == -1) {
            return queryTimeline(query_script, userId, "+inf", operation);
        }
        return queryTimeline(query_script, userId, sequence, operation);
    }

    @Override
    public Result queryMomentByMomentId(String momentId) {
        try {

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new SocialGramException(ResultEnum.INTERNAL_ERROR);
        }
        return null;
    }

    @Override
    public Result queryFriendMomentsByUserId(Long userId, Long sequence, Integer operation) {
        return queryTimeline(query_friend_script, userId, sequence, operation);
    }

    Result queryTimeline(DefaultRedisScript<List> script, Long userId, Object sequence, Integer operation) {
        try {
            Set<String> range = stringRedisTemplate.opsForZSet().range(userId + ":tls", -1, -1);
            if (range != null && range.size() > 0) {
                List<String> list = new ArrayList<>(range);
                String s = list.get(0);
                if (s.equals((sequence + "").trim())) {
                    return ResultUtils.success();
                }
            }
            List<String> moemntsJson = stringRedisTemplate.execute(script, null, new Object[]{
                    userId + "", sequence + "", operation + ""
            });
            List<Timeline> timelineList = new ArrayList<>();
            for (String json : moemntsJson) {
                timelineList.add(JsonUtils.jsonToPojo(json, Timeline.class));
            }
            List<Timeline> timelines = new ArrayList<>();
            if (timelineList != null && timelineList.size() > 0) {
                for (Timeline timeline : timelineList) {
                    if (timeline != null) {
                        if (timeline.getUserId() == -1) {//redis未命中，去elasticsearch查
                            String momentId = timeline.getMomentId();
                            GetQuery getQuery = new GetQuery();
                            getQuery.setId(momentId);
                            Moment m = elasticsearchTemplate.queryForObject(getQuery, Moment.class);
                            System.out.println(m.getPrice() + "元");
                            Timeline line = new Timeline(momentId, m.getMediaType(), m.getUserId(), m.getMedia_list(), m.getTextContent(),
                                    m.getSubject_list(), m.getAtSomeOne_list(), m.getLocation(), m.getLat(), m.getLon(),
                                    m.getIsPublic(), m.getPrice(), m.getCreateTime(), m.getCreateTimezone(), m.getOnTheTop(),
                                    timeline.getSeenCount(), timeline.getLikedCount(), timeline.getCommentsCount(), timeline.getGiftsCount());
                            timelines.add(timeline);
                        } else {
                            timelines.add(timeline);
                        }
                    }
                }
                return ResultUtils.success(timelines);
            } else {
                return ResultUtils.success();
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new SocialGramException(ResultEnum.INTERNAL_ERROR);
        }
    }
}
